package cn.openea.perpartner.rule.compile;

import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;

/**
 * 将编译好的.class文件保存到内存当中
 * 也就是保存到map映射当中
 * @author Weird077
 */
final class DynamicJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
    private final static String EXT = ".java";
    private boolean createClass;
    /**
     *  用于存放.class文件的内存
     */
    private Map<String, byte[]> classBytes;
    public DynamicJavaFileManager(JavaFileManager fileManager,boolean createClass) {
        super(fileManager);
        classBytes = new HashMap<>();
        this.createClass = createClass;
    }
    public Map<String, byte[]> getClassBytes() {
        return classBytes;
    }
    @Override
    public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind,
                                               FileObject sibling) throws IOException {

            return  this.createClass?super.getJavaFileForOutput(location, className, kind, sibling):new JavaClassObject(className);

    }
    /**
     * 来自字符串的 Java 源的文件对象。
     */
    private static class StringJavaFileObject extends SimpleJavaFileObject {
        //Java源代码
        final String content;
        //遵循Java规范的类名及文件
        StringJavaFileObject(String name, String content) {
            super(toURI(name), Kind.SOURCE);
            this.content = content;
        }
        @Override
        public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
            return CharBuffer.wrap(content);
        }
    }
    /**
     * 将 Java字节码存储到 classBytes 映射中的文件对象。
     */
    private class JavaClassObject extends SimpleJavaFileObject {
        private String name;
        JavaClassObject(String name) {
            super(toURI(name), Kind.CLASS);
            this.name = name;
        }
        @Override
        public OutputStream openOutputStream() {
            return new FilterOutputStream(new ByteArrayOutputStream()) {
                @Override
                public void close() throws IOException {
                    out.close();
                    ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
                    classBytes.put(name, bos.toByteArray());
                }
            };
        }
    }


    static JavaFileObject makeStringSource(String name, String code) {
        return new StringJavaFileObject(name, code);
    }

    static URI toURI(String name) {
        File file = new File(name);
        if (file.exists()) {
            return file.toURI();
        } else {
            try {
                final StringBuilder newUri = new StringBuilder();
                newUri.append("mfm:///").append(name.replace('.', '/'));
                if (name.endsWith(EXT)) {
                    newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
                }
                return URI.create(newUri.toString());
            } catch (Exception exp) {
                return URI.create("mfm:///com/sun/script/java/java_source");
            }
        }
    }
}